(function () {
  const systemPrototype = System.constructor.prototype;
  const originalInstantiate = systemPrototype.instantiate;
  var counter = 0;

  // 在我们的脚本里，动态引入脚本主要有两种类型： AMD 加载方法、全局脚本加载方法。对于 AMD 加载方法，
  // 主要用在自定义组件中，使用 define 全局关键字来识别，所以，在加载 AMD 模块前需要定义 define 关键字；对于非 AMD 加载的模块，例如大部分全局库，是直接写入全局变量的，如果遇到了 define 反而会报错，所以要去掉 define。
  // 为了避免异步并发场景下 define 被错误取消，所以引入了引用计数器，只有当计数器为 0 的时候，才真正销毁全局的 define
  systemPrototype.registerDynamic = define;
  self.define = undefined;

  systemPrototype.instantiate = function () {
    // const loader = this;
    const url = arguments[0];
    if (url.slice(-4) === '.css'){
      return new Promise(function(resolve, reject){
        if(
          document.querySelector('link[href="'+url+'"]') || 
          document.querySelector('link[href="'+url.replace(location.protocol+'//'+location.hostname, '')+'"]')
        ){
          reject(Error('Style '+url+' has already been loaded using another way.'));
          return;
        }
        let link = document.createElement('link');
        link.type = 'text/css';
        link.rel = 'stylesheet';
        link.href = url;
        document.head.appendChild(link);
        link.onload = function(){
          // console.log('%c Style '+url+' has been loaded', 'color: green');
          resolve([[], function (){
            return {};
          }]);
        };
        link.onerror = function(e) {
          let href = document.querySelector('link[href="'+url+'"]');
          if(href){
            href.parentElement.removeChild(href);
          }
          reject(e);
        };
      });
    } else {
      self.define = systemPrototype.registerDynamic;
      counter++;
      var p = originalInstantiate.apply(this, arguments);
      return Promise.resolve(p).then(function (ret) {
        if (--counter == 0) {
          self.define = undefined;
        }
        return ret;
      });
    }
  };

  const originalResolve = System.constructor.prototype.resolve;
  System.constructor.prototype.resolve = function (id) {
      return id;
  };
})();